#include "StdAfx.h"
#include "t_MessageQueue.h"



t_MessageQueue::t_MessageQueue(void)
{
	//SendMessage(NULL, int type, int msg, clock_t time)
	threadHandle = NULL;
	InitializeCriticalSection(&CriticalSection); 
}


t_MessageQueue::~t_MessageQueue(void)
{
	/* */
	if (threadHandle != NULL)
		StopThread();
	
	DeleteCriticalSection(&CriticalSection);
}

int t_MessageQueue::Poll()
{
	int processed = 0;
	int finished = 0;

	EnterCriticalSection(&CriticalSection);

	do {
		/* * */
		/* NO RETURN IS ALLOWED IN THIS CYCLE */
		/* Need to leave critical section before  returning from this procedure */
		/* * */

		list<t_Message>::iterator it = p_MessageList.begin();
		clock_t curr_time = clock();

		if (p_MessageList.empty()) 
			break;


		/* p_MessageList.end() - An iterator to the element ***past*** the end of the sequence. */
		while (!p_MessageList.empty() && (!finished) && (it != p_MessageList.end()))
		{


			/* if t_Message.p_Clock == 0  - message should be processed immediately */
			if ((it->GetTime() == 0) || (it->GetTime() <= curr_time))
			{

				if (it->GetRecipient()) 
					it->GetRecipient()->ProcessMessage(&*it);
				list<t_Message>::iterator cur = it;
				it++;
				p_MessageList.erase(cur);
				processed++;
				continue;
			}

			it++;
		}
	} while(0);

	LeaveCriticalSection(&CriticalSection);

	return processed;
}

int t_MessageQueue::Insert(const t_Message& msg)
{

	EnterCriticalSection(&CriticalSection);

	p_MessageList.push_back(msg);
	p_MessageList.end()->p_MessageQueue = this; /* msg->p_MessageQueue should be changed before insterting ! */
	p_MessageList.sort();

	LeaveCriticalSection(&CriticalSection);

	return 0;
}

int t_MessageQueue::SendMessage(t_MessageRecipient* p_MessageRecipient, int type, int msg, clock_t time)
{
	EnterCriticalSection(&CriticalSection);

	t_Message p_Message(p_MessageRecipient, type, msg, time);
	p_Message.p_MessageQueue = this;
	p_MessageList.push_back(p_Message);
	p_MessageList.sort();

	LeaveCriticalSection(&CriticalSection);

	return 0;
}

/*
t_Message t_MessageQueue::GetMessage(t_Message Recipient*)
{
}
*/

int t_MessageQueue::StartThread(void)
{
	if (threadHandle == NULL)
	 threadHandle = CreateThread (
            0, // Security attributes
            0, // Stack size
			&this->ThreadEntry,
            this,
            0,
            0);
	else
		return -1;
	return 0;
}

int t_MessageQueue::StopThread(void)
{
	if (threadHandle)
		CloseHandle(threadHandle);
	threadHandle = NULL;
	return 0;
}

DWORD WINAPI t_MessageQueue::ThreadEntry(void *pArg)
{
	t_MessageQueue *p_MessageQueue = (t_MessageQueue*)pArg;

	while (1)
	{
		p_MessageQueue->Poll();
		SleepEx(10,false);
	}
}
